/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package packer;

import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
 *
 * @author Bartek
 */
public class PackerOutputStream extends FilterOutputStream {
    
    public PackerOutputStream(OutputStream out) {
        super(out);
    }
    
    @Override
    public void write(byte[] bytes, int off, int len) throws IOException {
//        byte[] bytesToProcess = null;
//        int numOfBytesToAdd = bytes.length % 4;
//        
//        if (numOfBytesToAdd != 0) {
//            bytesToProcess = new byte[bytes.length + numOfBytesToAdd];
//            
//            System.arraycopy(bytes, 0, bytesToProcess, 0, bytes.length);
//            
//            for (int i = bytes.length; i < bytesToProcess.length; i++) {
//                bytesToProcess[i] = 0;
//            }
//        }
//        else
//        {
//            bytesToProcess = bytes;
//        }
        
        StringBuilder compressedBinaryStringBuilder = new StringBuilder();
       
        final int START_INDEX = 2;
        
        for (int i = 0; i < len; i++) {
            byte characterCode = getCharacterCode(bytes[i]);
            String binaryString = String.format("%8s", 
                    Integer.toBinaryString(characterCode & 0xFF)).replace(' ', '0')
                    .substring(START_INDEX);
            
            compressedBinaryStringBuilder.append(binaryString);
        }
        
        while (compressedBinaryStringBuilder.length() % 8 != 0) {
            compressedBinaryStringBuilder.append("0");
        }
        
        String compressedBinaryString = compressedBinaryStringBuilder.toString();
        
        byte [] compressedBytes = new byte[(int)(3.0 * Math.ceil(len / 4.0))];
        
        for (int i = 0; i < compressedBinaryString.length(); i += 8) {
            compressedBytes[i/8] = (byte)Integer.parseInt(compressedBinaryString.substring(i, i + 8), 2);
        }
        
        super.out.write(compressedBytes, 0, compressedBytes.length);
    }
    
    private byte getCharacterCode(byte characterByte) {
        
        char character = (char)characterByte;
        byte characterCode;
        
	switch(character){
		case' ':characterCode=0;break; case'a':characterCode=1;break;
		case'b':characterCode=2;break; case'c':characterCode=3;break;
		case'd':characterCode=4;break; case'e':characterCode=5;break;
		case'f':characterCode=6;break; case'g':characterCode=7;break;
		case'h':characterCode=8;break; case'i':characterCode=9;break;
		case'j':characterCode=10;break; case'k':characterCode=11;break;
		case'l':characterCode=12;break; case'm':characterCode=13;break;
		case'n':characterCode=14;break; case'o':characterCode=15;break;
		case'p':characterCode=16;break; case'q':characterCode=17;break;
		case'r':characterCode=18;break; case's':characterCode=19;break;
		case't':characterCode=20;break; case'u':characterCode=21;break;
		case'v':characterCode=22;break; case'w':characterCode=23;break;
		case'x':characterCode=24;break; case'y':characterCode=25;break;
		case'z':characterCode=26;break; case'.':characterCode=27;break;
		case'*':characterCode=28;break; case',':characterCode=29;break;
		case'\\':characterCode=30;break; case'2':characterCode=31;break;
		case'A':characterCode=32;break; case'B':characterCode=33;break;
		case'C':characterCode=34;break; case'D':characterCode=35;break;
		case'E':characterCode=36;break; case'F':characterCode=37;break;
		case'G':characterCode=38;break; case'H':characterCode=39;break;
		case'I':characterCode=40;break; case'J':characterCode=41;break;
		case'K':characterCode=42;break; case'L':characterCode=43;break;
		case'M':characterCode=44;break; case'N':characterCode=45;break;
		case'O':characterCode=46;break; case'P':characterCode=47;break;
		case'Q':characterCode=48;break; case'R':characterCode=49;break;
		case'S':characterCode=50;break; case'T':characterCode=51;break;
		case'U':characterCode=52;break; case'V':characterCode=53;break;
		case'W':characterCode=54;break; case'0':characterCode=55;break;
		case'1':characterCode=56;break; case'3':characterCode=57;break;
		case'4':characterCode=58;break;case'5':characterCode=59;break;
		case'6':characterCode=60;break;case'7':characterCode=61;break;
		case'8':characterCode=62;break;case'9':characterCode=63;break;
		default:characterCode=28;
	}
	return characterCode;
    }
}
